package collector

import (
	"errors"
	"fmt"
	"github.com/rancher/go-rancher/v2"
	"net/url"
	"strings"
)

var (
	errNoEnv = errors.New("Failed to find the current environment")
)

type Config struct {
	AccessKey  string `json:"accessKey"`
	SecretKey  string `json:"secretKey"`
	URL        string `json:"url"`
	WsUrl      string `json:"wsUrl"`
	RancherEnv string `json:"rancherEnv"`
}

func GetEnvironment(def string, c *client.RancherClient) (*client.Project, error) {
	resp, err := c.Project.List(nil)
	if err != nil {
		return nil, err
	}

	if len(resp.Data) == 0 {
		return nil, errNoEnv
	}

	if len(resp.Data) == 1 {
		return &resp.Data[0], nil
	}

	return LookupEnvironment(c, def)
}

func LookupEnvironment(c *client.RancherClient, name string) (*client.Project, error) {
	env, err := Lookup(c, name, "project")
	if err != nil {
		return nil, err
	}
	return c.Project.ById(env.Id)
}

func Lookup(c *client.RancherClient, name string, types ...string) (*client.Resource, error) {
	var byName *client.Resource

	for _, schemaType := range types {
		var resource client.Resource
		if err := c.ById(schemaType, name, &resource); !client.IsNotFound(err) && err != nil {
			return nil, err
		} else if err == nil && resource.Id == name { // The ID check is because of an oddity in the id obfuscation
			return &resource, nil
		}

		var collection client.ResourceCollection

		listOpts := &client.ListOpts{
			Filters: map[string]interface{}{
				"name":         name,
				"removed_null": 1,
			},
		}
		if schemaType == "project" {
			listOpts.Filters["all"] = true
		}

		if err := c.List(schemaType, listOpts, &collection); err != nil {
			return nil, err
		}

		if len(collection.Data) > 1 {
			ids := []string{}
			for _, data := range collection.Data {
				ids = append(ids, data.Id)
			}
			return nil, fmt.Errorf("Multiple resources of type %s found for name %s: %v", schemaType, name, ids)
		}

		if len(collection.Data) == 0 {
			continue
		}

		if byName != nil {
			return nil, fmt.Errorf("Multiple resources named %s: %s:%s, %s:%s", name, collection.Data[0].Type,
				collection.Data[0].Id, byName.Type, byName.Id)
		}

		byName = &collection.Data[0]
	}

	if byName == nil {
		return nil, fmt.Errorf("Not found: %s", name)
	}

	return byName, nil
}

func baseURL(fullURL string) (string, error) {
	idx := strings.LastIndex(fullURL, "/v2-beta")
	if idx == -1 {
		u, err := url.Parse(fullURL)
		if err != nil {
			return "", err
		}
		newURL := url.URL{
			Scheme: u.Scheme,
			Host:   u.Host,
		}
		return newURL.String(), nil
	}
	return fullURL[:idx], nil
}

func (c *Config) EnvironmentURL() (err error) {
	projectID := c.RancherEnv
	if projectID == "" || !strings.HasPrefix(projectID, "1a") {
		rancherClient, err := client.NewRancherClient(&client.ClientOpts{
			Url:       c.URL,
			AccessKey: c.AccessKey,
			SecretKey: c.SecretKey,
		})
		if err != nil {
			return err
		}
		project, err := GetEnvironment(c.RancherEnv, rancherClient)
		if err != nil {
			return err
		}
		projectID = project.Id
	}

	c.WsUrl, err = baseURL(c.URL)
	c.WsUrl = c.WsUrl + "/v2-beta/projects/" + projectID + "/schemas"

	return err
}
